#ifndef GAMEENGINE_GEOMETRY_BOX3D_H
#define GAMEENGINE_GEOMETRY_BOX3D_H

#include <GameEngine/Geometry/geometry_settings.h>

#include <GameEngine/Geometry/Location/point3d.h>
#include <GameEngine/Geometry/Core/coords3d.h>
#include <GameEngine/Geometry/Lines/line3d.h>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif

namespace Box3D {
	//! Point index along a 3D box
	enum Index {
		//! First point
		/*!
		 @note This is the bottom-left-down point of the box
		 */
		First = 0,
		//! Second point
		/*!
		 @note This is the top-left-down point of the box
		 */
		Second = 1,
		//! Third point
		/*!
		 @note This is the bottom-right-down point of the box
		 */
		Third = 2,
		//! Fourth point
		/*!
		 @note This is the top-right-down point of the box
		 */
		Fourth = 3,
		//! Fifth point
		/*!
		 @note This is the bottom-left-up point of the box
		 */
		Fifth = 4,
		//! Sixth point
		/*!
		 @note This is the top-left-up point of the box
		 */
		Sixth = 5,
		//! Seventh point
		/*!
		 @note This is the bottom-right-up point of the box
		 */
		Seventh = 6,
		//! Eighth point
		/*!
		 @note This is the top-right-up point of the box
		 */
		Eighth = 7
	};
}



//! Class used to represent an axis-aligned 3D box
/*!
 *  A 3D box whose axes are aligned on the X, Y and Z axes.
 *
 @note Most algorithms expect floating point operations. Type T should therefore
       not be an integer type
 */
template <class T>
class Box3d {

public:
	Box3d();
	Box3d(const T& x_min, const T& x_max, const T& y_min, const T& y_max, const T& z_min, const T& z_max);
	Box3d(const Point3d<T>& bottom_left_down, const Point3d<T>& top_right_up);
	Box3d(const Box3d& rhs);
	virtual ~Box3d();
	Box3d& operator=(const Box3d& rhs);

	Point3d<T> bottom_left_down() const;
	Point3d<T> bottom_right_down() const;
	Point3d<T> top_left_down() const;
	Point3d<T> top_right_down() const;
	Point3d<T> bottom_left_up() const;
	Point3d<T> bottom_right_up() const;
	Point3d<T> top_left_up() const;
	Point3d<T> top_right_up() const;

	T min_x() const;
	T max_x() const;
	T min_y() const;
	T max_y() const;
	T min_z() const;
	T max_z() const;

	Point3d<T> point(const Coords3d<T>& coords) const;
	Point3d<T> operator[](Box3D::Index index) const;

	bool inside(const Point3d<T>& rhs, bool strict = false) const;
	bool overlap(const Box3d& rhs) const;
//	int intersection(const Line3d<T>& rhs, T& line_coordinate1, T& line_coordinate2, IntersectionType::Type* type = nil) const;
	bool closest_point(const Point3d<T>& rhs, Coords3d<T>& coords) const;
	Point3d<T> closest_point(const Point3d<T>& rhs) const;

	T area() const;
	T volume() const;

	bool degenerate(const T& tolerance = 0.000001) const;
	static bool in_box(const Coords3d<T>& coords, bool strict=false);

protected:
	//! Bottom-left-down point of the box
	Point3d<T> bottom_left_down_;

	//! Top-right-up point of the box
	Point3d<T> top_right_up_;
};

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#include <GameEngine/Geometry/Volumes/box3d.hpp>

#endif
